package com.passby;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Map;

import net.oauth.OAuth;
import net.oauth.OAuthAccessor;
import net.oauth.OAuthConsumer;
import net.oauth.OAuthException;
import net.oauth.OAuthMessage;
import net.oauth.OAuthServiceProvider;
import net.oauth.client.OAuthClient;
import net.oauth.client.httpclient4.HttpClient4;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.location.Location;

import com.PassByUtiles;
import com.google.android.maps.GeoPoint;

import data.PassByItem;
import data.User;

public class Client{
	public static Boolean REAL_TIME_SET_ME_CENTER = true;
	private static Client instance;
	
	public User self;
	public Hashtable<String, User> users;
	private static String MAIN_URL = "http://10.0.2.2:8080";
	
	private static String ACCESS_TOKEN_URL = MAIN_URL + "/oauth/access_token";
	private static String OAUTH_SIGNIN_URL = MAIN_URL + "/oauth/oauth_signin";
	private static String QUERY_USER = MAIN_URL + "/api/user/queryuser";
	private static String UPDATE_LOCATION = MAIN_URL + "/api/user/updateuserlocation";
	private static String QUERY_LOCAL_USERS = MAIN_URL + "/api/user/querylocalusers";
	private static String UPDATE_LOCAL_USERS = MAIN_URL + "/api/user/updatelocalusers";
	private static String CREATE_ITEM_URL = MAIN_URL + "/api/luckyItem/creatItem";
	private static String SIGNOUT_URL = MAIN_URL + "/oauth/signout";
	private static OAuthClient client = new OAuthClient(new HttpClient4());
	public static OAuthAccessor accessor;
	
	private Client()
	{
		users = new Hashtable<String, User>();
	}
	
	public static Client getInstance()
	{
		if(instance == null)
		{
			instance = new Client();
		}
		return instance;
	}
	
	public boolean login(String username,String password)
	{
		final OAuthServiceProvider provider = new OAuthServiceProvider(null,null,ACCESS_TOKEN_URL);
		final OAuthConsumer consumer = new PassByConsumer(null, provider);
        try {
        	 accessor = new OAuthAccessor(consumer);
             Collection<? extends Map.Entry> parameters =  OAuth.newList("x_auth_username", username //
                     , "x_auth_password", password //
             );
			OAuthMessage response = client.invoke(accessor, OAuthMessage.POST,
			        accessor.consumer.serviceProvider.accessTokenURL, parameters);
			String content = response.readBodyAsString();
			content = PassByUtiles.toUtf8(content);
			JSONObject c = new JSONObject(content);
			String token = c.getString("access_token");
			String token_secret = c.getString("access_token_secret");
			JSONObject user = c.getJSONObject("user");
			self = new User();
			self.username = user.getString("username");
			self.email = user.getString("email");
			self.nickname = user.getString("nickname");
			self.mark = user.getString("mark");
			self.avatarUrl = user.getString("avatarUrl");
			self.id = user.getString("id");
			self.gender = user.getInt("gender");
			String p = user.getString("location");
			float lat = Float.parseFloat(p.split(",")[0]);
			float lon = Float.parseFloat(p.split(",")[1]);
			self.location = new GeoPoint((int) (lat * 1000000), (int)(lon * 1000000));
			JSONObject item = c.getJSONObject("current_item");
			self.addItem(PassByItem.decode(item));
			accessor.accessToken = token;
			accessor.tokenSecret = token_secret;
			return true;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (OAuthException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (URISyntaxException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return false;
	}
	
	public boolean logout()
	{
		boolean success = false;
		try {
			String resutl = request(SIGNOUT_URL, null, OAuthMessage.POST);
			JSONObject it = new JSONObject(resutl);
			success = it.getBoolean("result");
		}catch (JSONException e) {
			e.printStackTrace();
		}
		return success;
	}
	
	public boolean loginWithToken(String accessToken,String token_secret)
	{
		final OAuthServiceProvider provider = new OAuthServiceProvider(null,null,ACCESS_TOKEN_URL);
		final OAuthConsumer consumer = new PassByConsumer(null, provider);
		try {
       	 	accessor = new OAuthAccessor(consumer);
       	 	accessor.accessToken = accessToken;
			accessor.tokenSecret = token_secret;
			String content = request(OAUTH_SIGNIN_URL, null, OAuthMessage.POST);
			JSONObject c = new JSONObject(content);
			JSONObject user = c.getJSONObject("user");
			self = new User();
			self.username = user.getString("username");
			self.email = user.getString("email");
			self.nickname = user.getString("nickname");
			self.mark = user.getString("mark");
			self.avatarUrl = user.getString("avatarUrl");
			self.id = user.getString("id");
			self.gender = user.getInt("gender");
			String p = user.getString("location");
			float lat = Float.parseFloat(p.split(",")[0]);
			float lon = Float.parseFloat(p.split(",")[1]);
			JSONObject item = c.getJSONObject("current_item");
			self.addItem(PassByItem.decode(item));
			self.location = new GeoPoint((int) (lat * 1000000), (int)(lon * 1000000));
			return true;
		}catch (JSONException e) {
			e.printStackTrace();
		}
		return false;
	}
	
	public boolean sendItem(String content)
	{
		try {
			Collection<? extends Map.Entry> parameters =  OAuth.newList("content", content //
						, "location", PassByUtiles.encodeGeoPt(self.location) //
            );
			String resutl = request(CREATE_ITEM_URL, parameters, OAuthMessage.POST);
			JSONObject it = new JSONObject(resutl);
			boolean success = it.getBoolean("result");
			if(success)
			{
				self.addItem(PassByItem.decode(it));
			}
			return true;
		}catch (JSONException e) {
			e.printStackTrace();
		}
		return false;
	}
	
	private String request(String url, Collection<? extends Map.Entry> param, String method)
	{
		try {
			OAuthMessage response1 = client.invoke(accessor, OAuthMessage.POST,
					url, param);
			String result = response1.readBodyAsString();
			result = PassByUtiles.toUtf8(result);
			return result;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return "";
		} catch (OAuthException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return "";
		} catch (URISyntaxException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return "";
		}
	}
	
	public Boolean updateLocation(Location location)
	{
		 @SuppressWarnings("rawtypes")
		Collection<? extends Map.Entry> parameters1 =  OAuth.newList("location", Double.toString(location.getLatitude())+","+Double.toString(location.getLongitude())
	            );
		String result_str = request(UPDATE_LOCATION, parameters1, OAuthMessage.POST);
		try {
			JSONObject result = new JSONObject(result_str);
			if(result.getBoolean("result"))
			{
				String p = result.getString("location");
				float lat = Float.parseFloat(p.split(",")[0]);
				float lon = Float.parseFloat(p.split(",")[1]);
				self.location = new GeoPoint((int) (lat * 1000000), (int)(lon * 1000000));
			}
			return result.getBoolean("result");
		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		}
	}
	
	public boolean queryLocalUsers(GeoPoint location)
	{
		String lat = Double.toString(location.getLatitudeE6()/1E6);
		String lon = Double.toString(location.getLongitudeE6()/1E6);
		Collection<? extends Map.Entry> parameters =  OAuth.newList("location", lat+","+lon
	            );
		String result_str = request(QUERY_LOCAL_USERS, parameters, OAuthMessage.POST);
		try {
			JSONObject result = new JSONObject(result_str);
			if(result.getBoolean("result"))
			{
				JSONArray jusers = result.getJSONArray("users");
				for(int i=0;i<jusers.length();i++)
				{
					JSONObject  jsonUser = jusers.getJSONObject(i);
					User user = User.decodeUser(jsonUser);
					users.put(user.username, user);
				}
			}
			return result.getBoolean("result");
		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		}
	}
	
	public boolean updateLocalUsers(GeoPoint location)
	{
		String lat = Double.toString(location.getLatitudeE6()/1E6);
		String lon = Double.toString(location.getLongitudeE6()/1E6);
		Collection<? extends Map.Entry> parameters =  OAuth.newList("location", lat+","+lon
	            );
		String result_str = request(QUERY_LOCAL_USERS, parameters, OAuthMessage.POST);
		try {
			JSONObject result = new JSONObject(result_str);
			if(result.getBoolean("result"))
			{
				JSONArray users = result.getJSONArray("users");
				for(int i=0;i<users.length();i++)
				{
					JSONObject  jsonUser = users.getJSONObject(i);
					User user = User.decodeUser(jsonUser);
				}
			}
			return result.getBoolean("result");
		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		}
	}
	
	public void sendMessage(String message)
	{
		
	}

	public void reset() {
		this.self = null;
		accessor = null;
	}
}
